package oop.ex3.usercommands;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.LinkedList;

import oop.ex3.filemanager.FileManager;
import oop.ex3.protocol.Begin;
import oop.ex3.protocol.ClientMessageSender;
import oop.ex3.protocol.ContainFile;
import oop.ex3.protocol.WantFile;
import oop.ex3.protocol.WantServers;
import oop.ex3.sharedclasses.IPaddress;

public class Add extends UserMessage {

	public static final String COMMAND="ADD";
	private static final int TIME_OUT = 5000;
	private String _fileName;
	private LinkedList<IPaddress> _knownNameServers;
	private LinkedList<IPaddress> _usedNameServers;
	
	/**
	 * Constructs a new Add userCommand.
	 * sets fileName as the command's file-name.
	 * @param fileManager the FileManager using this UserMessage.
	 * @param fileName the fileName to be added.
	 */
	public Add(FileManager fileManager, String fileName) {
		super(fileManager);
		this._usedNameServers = new LinkedList<IPaddress>();
		this._knownNameServers = fileManager.getNameServerList();
		this._fileName=fileName;
	}

	@Override
	public boolean run() {
		if (_fileManager.contains(_fileName)!=null){
			System.out.println("File already exists");
			return SUCCESS;
		}
		
		LinkedList<IPaddress> fileAddress;
		WantFile askForFile = new WantFile();
		oop.ex3.protocol.File downloader = new oop.ex3.protocol.File();
		
		for (IPaddress nameServer : _knownNameServers){
			if (wasNameServerUsed(nameServer)){
				continue;
			}
			addToUsed(nameServer);
			fileAddress = askForFile.runAsClient(_fileManager, nameServer, _fileName);
			if (fileAddress==null){
				continue; //Server responded with file not found / session failed.
			}
			
			for (IPaddress sourceIP : fileAddress){
				if (downloader.runAsClient(_fileManager, sourceIP, _fileName)==SUCCESS){
					notifyFileWasDownloaded(_fileManager);
					System.out.println("File Downloaded Successfully from "
							+sourceIP.getIP()+":"+sourceIP.getPort());
					return SUCCESS;
				}
			}
		}
	
		WantServers serverAsker = new WantServers();
		
		LinkedList<IPaddress> temporaryServers = new LinkedList<IPaddress>();
		
		boolean foundNewServer = false;
		
		for (IPaddress nameServer : _knownNameServers){
			temporaryServers.addAll(
					serverAsker.runAsClient(_fileManager, nameServer));
			for (IPaddress ns : temporaryServers){
				if (!_fileManager.knowsNameServer(ns)){
					foundNewServer=true;
					_fileManager.addNameServer(ns);
				}
			}
		}
		_knownNameServers = _fileManager.getNameServerList();
		if (foundNewServer){
			return run();
		}else{
			System.out.println("Downloading failed");
			return FAILURE;
		}
	}

	private void notifyFileWasDownloaded(FileManager _fileManager) {
		// TODO Auto-generated method stub
		LinkedList<IPaddress> knownNameServers = _fileManager.getNameServerList();
		ContainFile notifier = new ContainFile();
		for (IPaddress knownNS : knownNameServers){
			notifier.runAsClient(_fileManager, knownNS, _fileName);
		}
	}

	/**
	 * Adds a nameServer to the Used list.
	 * @param nameServer the name server to be added.
	 */
	private void addToUsed(IPaddress nameServer){
		_usedNameServers.add(nameServer);
	}
	
	/**
	 * Returns whether this server was already searched or not.
	 * @param nameServer the nameserver to be checked.
	 * @return true if was used, false otherwise.
	 */
	private boolean wasNameServerUsed(IPaddress nameServer){
		for (IPaddress used : _usedNameServers){
			if (nameServer.equals(used)){
				return true;
			}
		}
		return false;
	}

}
